/**
 *******************************************************************************
 * @file  timer6/timer6_define_pwm_number/source/main.c
 * @brief This example demonstrates Timer6 compare output indicated number PWM pulses.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2022-03-31       CDT             First version
   2023-01-15       CDT             Modify structure stc_timer6_init_t to stc_tmr6_init_t
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2022-2023, Xiaohua Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by XHSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "ws2812b.h"

/**
 * @addtogroup HC32F460_DDL_Examples
 * @{
 */
static void Tmr6_OverFlow_CallBack(void);
/**
 * @addtogroup TIMER6_define_pwm_number
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

#define TMR6_1_PWMA_PORT (GPIO_PORT_A)
#define TMR6_1_PWMA_PIN (GPIO_PIN_08)

#define TMR6_1_PWMB_PORT (GPIO_PORT_A)
#define TMR6_1_PWMB_PIN (GPIO_PIN_07)

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/

init_rgb_set rgb_set;
link *rgb_link;
/**
 * @func:
 * @description: 启动脉冲发送
 * @return {*}
 * @example:
 */
void run_ws2812b(void)
{
    init_rgb_set *p_rgb = &rgb_set;

    switch (p_rgb->LED_MODE)
    {
    case LED_FLOW /* constant-expression */:
        /* 获取需要点亮灯的个数 */
        uint16_t index = (uint16_t)get_apm_value(p_rgb->move_index, LED_QTY, LED_QTY << 1, p_pwm->data);
        /* 灯带增加 */
        if (index > p_rgb->index_qty)
        {
            p_rgb->index_qty = index;
            do
            {
                /* code */
                p_rgb->color[index] = p_rgb->color_set[p_rgb->color_index];
            } while (--index /* condition */);
        } /* 灯带减少 */
        else if (index < p_rgb->index_qty)
        {

            do
            {
                /* code */
                p_rgb->color[p_rgb->index_qty--] = 0;
            } while (index < p_rgb->index_qty /* condition */);

            /* 换颜色 */
            if (index == 0)
            {
                p_rgb->move_index = 0;
                if (++p_rgb->color_index > 6)
                    p_rgb->color_index = 0;
                p_rgb->index_qty = index;
                p_rgb->color[index] = p_rgb->color_set[p_rgb->color_index];
            }
        }
        p_rgb->move_index++;
        DDL_DelayMS(5);
        break;
    case LINK_FLOW /* constant-expression */:

        /* 销毁链表重新开始 */
        if (p_rgb->link_len >= LED_QTY)
        {

            /* 清屏p_rgb->color 为4字节 */
            //  memset(p_rgb->color, 0, sizeof(p_rgb->color));
            // rgb_link = disposal_LinkList(rgb_link);
            // rgb_link = set_link_brightness_init(p_rgb->link_rgb_data, sizeof(p_rgb->link_rgb_data) / sizeof(uint32_t));
            // /*  重新获取长度 */
            // p_rgb->link_len = display_lenth(rgb_link);
            // printf(" p_rgb->len= %d \r\n", p_rgb->len);
            delElem(rgb_link,p_rgb->link_len);
        }
        /* 按每上升1个灯 */
        if (++p_rgb->color_flag >= LINK_INIT_LEN)
            p_rgb->color_flag = 0;
        rgb_link = insertElem(rgb_link, p_rgb->color_set[LINK_INIT_LEN - p_rgb->color_flag++], 1);
        p_rgb->link_len = display_lenth(rgb_link);
        /* 重新赋值 */
        list_conver_to_arr(rgb_link, p_rgb->color, p_rgb->link_len);

        DDL_DelayMS(15);
        break;
    case GRAD_COLOR /* constant-expression */:
        /* code */
        uint32_t scolor = change_level(p_rgb->color_set[p_rgb->color_flag], p_rgb->brightness);
        if (1.0 < p_rgb->brightness)
        {
            if (++p_rgb->color_flag > 6)
            {
                p_rgb->color_flag = 0;
                p_rgb->LED_MODE = BRIGHTNESS;
                p_rgb->blue_index = 0xff;
            }
            p_rgb->brightness = 0.00;
            DDL_DelayMS(50);
        }
        p_rgb->brightness += 0.1;

        for (uint32_t i = 0; i < LED_QTY; i++)
            p_rgb->color[i] = scolor;
        DDL_DelayMS(6);
        break;
    case BRIGHTNESS /* constant-expression */:
        /* code */
        switch (p_rgb->brightness_index)
        {
        case 0 /* constant-expression */:
            /* code */
            if (0xff == p_rgb->red_index)
                p_rgb->brightness_index++;
            else
            {
                ++p_rgb->red_index;
                --p_rgb->blue_index;
            }
            break;
        case 1 /* constant-expression */:
            /* code */
            if (0xff == p_rgb->green_index)
                p_rgb->brightness_index++;
            else
            {
                ++p_rgb->green_index;
                --p_rgb->red_index;
            }
            break;
        case 2 /* constant-expression */:
            /* code */
            if (0xff == p_rgb->blue_index)
                p_rgb->brightness_index++;
            else
            {
                ++p_rgb->blue_index;
                --p_rgb->green_index;
            }
            break;
        default:
            p_rgb->brightness_index = 0;
            p_rgb->LED_MODE = BRIGHTNESS;
            break;
        }
        uint32_t color = color_uint8_uint32(p_rgb->red_index, p_rgb->green_index, p_rgb->blue_index);
        for (uint32_t i = 0; i < LED_QTY; i++)
        {
            p_rgb->color[i] = color;
        }
        break;
    default:
        break;
    }

    /* 第1个脉冲 23 bit */
    p_rgb->bit24 = 23;
    p_rgb->led_index = 0;

    /* 设置第1个脉冲第23位 */
    if (p_rgb->color[p_rgb->led_index] & (1 << p_rgb->bit24))
        TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, 172);
    else
        TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, 74);

    /* 开启脉冲计数 */
    TMR6_Start(CM_TMR6_2);
    TMR6_Start(CM_TMR6_1);

    return;
}

/**
 * @brief  TIMER6 overflow interrupt handler callback.
 * @param  None
 * @retval None
 */
static void Tmr6_OverFlow_CallBack(void)
{
    init_rgb_set *p_rgb = &rgb_set;
    /* 下一个24位数据 */
    if (p_rgb->bit24 == 0)
    {
        p_rgb->led_index += 1;
        p_rgb->bit24 = 23;
    }
    else
        p_rgb->bit24 -= 1;

    // 第0-22 bit
    if (p_rgb->color[p_rgb->led_index] & (1 << p_rgb->bit24))
        TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, 172);
    else
        TMR6_SetCompareValue(CM_TMR6_1, TMR6_CMP_REG_C, 74);

    return;
}

/**
 * @brief  Main function of TIMER6 compare output mode project
 * @param  None
 * @retval int32_t return value, if needed
 */
void init_ws2812b(void)
{
    stc_tmr6_init_t stcTmr6Init;
    stc_tmr6_pwm_init_t stcPwmInit;
    stc_irq_signin_config_t stcIrqRegiConf;

    (void)TMR6_StructInit(&stcTmr6Init);
    (void)TMR6_PWM_StructInit(&stcPwmInit);

    FCG_Fcg2PeriphClockCmd(FCG2_PERIPH_TMR6_1 | FCG2_PERIPH_TMR6_2, ENABLE);
    FCG_Fcg0PeriphClockCmd(PWC_FCG0_AOS, ENABLE);

    /* Timer6 PWM output port configuration */
    GPIO_SetFunc(TMR6_1_PWMA_PORT, TMR6_1_PWMA_PIN, GPIO_FUNC_3);

    /* Timer6 trigger event set */
    AOS_SetTriggerEventSrc(AOS_TMR6_0, EVT_SRC_TMR6_2_OVF); /* Set EVT_SRC_TMR6_2_OVF Event as Timer6 Trigger Source 0 */
    AOS_SetTriggerEventSrc(AOS_TMR6_1, EVT_SRC_TMR6_1_OVF); /* Set EVT_SRC_TMR6_1_OVF Event as Timer6 Trigger Source1 */

    /* Timer6 general count function configuration */
    stcTmr6Init.sw_count.u32ClockDiv = TMR6_CLK_DIV1;
    stcTmr6Init.u32PeriodValue = 246; /* Count for 800K */
    (void)TMR6_Init(CM_TMR6_1, &stcTmr6Init);

    /* Config hardware count */
    (void)TMR6_StructInit(&stcTmr6Init);
    stcTmr6Init.u8CountSrc = TMR6_CNT_SRC_HW;
    stcTmr6Init.hw_count.u32CountUpCond = TMR6_CNT_UP_COND_EVT1;
    stcTmr6Init.u32PeriodValue = LED_QTY * RGB_BIT;
    (void)TMR6_Init(CM_TMR6_2, &stcTmr6Init);

    /* General compare buffer function configure */
    TMR6_SetGeneralBufNum(CM_TMR6_1, TMR6_CH_A, TMR6_BUF_SINGLE);
    TMR6_GeneralBufCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);

    /* Configure PWM output */
    stcPwmInit.u32CompareValue = 0;
    stcPwmInit.u32PeriodMatchPolarity = TMR6_PWM_HIGH;
    stcPwmInit.u32CompareMatchPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32StopPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32StartPolarity = TMR6_PWM_LOW;
    stcPwmInit.u32StartStopHold = TMR6_PWM_START_STOP_CHANGE;
    (void)TMR6_PWM_Init(CM_TMR6_1, TMR6_CH_A, &stcPwmInit);
    /* PWM pin function set */
    TMR6_SetFunc(CM_TMR6_1, TMR6_CH_A, TMR6_PIN_CMP_OUTPUT);
    // TMR6_SetFunc(CM_TMR6_1, TMR6_CH_B, TMR6_PIN_CMP_OUTPUT);
    /* PWM output command */
    TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_A, ENABLE);
    // TMR6_PWM_OutputCmd(CM_TMR6_1, TMR6_CH_B, ENABLE);

    /* Enable interrupt */
    TMR6_IntCmd(CM_TMR6_1, TMR6_INT_OVF, ENABLE);
    TMR6_IntCmd(CM_TMR6_2, TMR6_INT_OVF, ENABLE);
    stcIrqRegiConf.enIRQn = INT002_IRQn;
    stcIrqRegiConf.enIntSrc = INT_SRC_TMR6_1_OVF;
    stcIrqRegiConf.pfnCallback = &Tmr6_OverFlow_CallBack;
    (void)INTC_IrqSignIn(&stcIrqRegiConf);
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIO_14);
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);

    /* Timer6 hardware trigger source configuration */
    TMR6_HWStopCondCmd(CM_TMR6_1, TMR6_STOP_COND_EVT0, ENABLE); /* CM_TMR6_1 Hardware Stop Event Condition: Timer6 Trigger Source 0(EVT_SRC_TMR6_2_OVF) */
    TMR6_HWStopCmd(CM_TMR6_1, ENABLE);

    TMR6_HWClearCondCmd(CM_TMR6_1, TMR6_CLR_COND_EVT0, ENABLE); /* CM_TMR6_1 Hardware Clear Event Condition: Timer6 Trigger Source0(EVT_SRC_TMR6_2_OVF) */
    TMR6_HWClearCmd(CM_TMR6_1, ENABLE);

    /* Start timer6 */
    TMR6_Stop(CM_TMR6_2);
    TMR6_Stop(CM_TMR6_1);

    init_rgb_set *p_rgb = &rgb_set;
    p_rgb->LED_MODE = LINK_FLOW;
    inint_mode(p_rgb->LED_MODE);

    rgb_link = set_link_brightness_init(p_rgb->link_rgb_data, sizeof(p_rgb->link_rgb_data) / sizeof(uint32_t));

    return;
}
/**
 * @func:
 * @description: 初始化模式
 * @param {FLASH_MODE} LED_MODE
 * @return {*}
 * @example:
 */
void inint_mode(FLASH_MODE LED_MODE)
{
    init_rgb_set *p_rgb = &rgb_set;
    switch (LED_MODE)
    {
    case LED_FLOW /* constant-expression */:
        /* code */
        p_rgb->color_set[0] = 0xff0000;
        p_rgb->color_set[1] = 0xff0000;
        p_rgb->color_set[2] = 0xff0000;
        p_rgb->color_set[3] = 0xff0000;
        p_rgb->color_set[4] = 0x00ff00;
        p_rgb->color_set[5] = 0x0000ff;
        p_rgb->color_set[6] = 0xff00ff;
        p_rgb->color_set[7] = 0xffff00;
        p_rgb->color_set[8] = 0x00ffff;
        p_rgb->color_set[9] = 0xffff00;
        p_rgb->color_set[10] = 0xff00ff;
        p_rgb->color_set[11] = 0xffffff;
        p_rgb->color_set[12] = 0xffffff;
        break;
    case LINK_FLOW /* constant-expression */:
        /* code */
        p_rgb->color_set[0] = 0;
        p_rgb->color_set[1] = 0;
        p_rgb->color_set[2] = 0;
        p_rgb->color_set[3] = 0;
        p_rgb->color_set[4] = 0x00ff00;
        p_rgb->color_set[5] = 0x00ff00;
        p_rgb->color_set[6] = 0x00ff00;
        p_rgb->color_set[7] = 0xff0000;
        p_rgb->color_set[8] = 0xff0000;
        p_rgb->color_set[9] = 0x0000ff;
        p_rgb->color_set[10] = 0x0000ff;
        p_rgb->color_set[11] = 0xff00ff;
        p_rgb->color_set[12] = 0xff00ff;
        p_rgb->color_set[13] = 0xff00ff;
        p_rgb->color_set[14] = 0xffff00;
        p_rgb->color_set[15] = 0x00ffff;
        p_rgb->color_set[16] = 0xffff00;
        p_rgb->color_set[17] = 0xff00ff;
        p_rgb->color_set[18] = 0xffffff;
        p_rgb->color_set[19] = 0xffffff;
        break;
    case GRAD_COLOR /* constant-expression */:
        /* code */
        p_rgb->color_set[0] = 0xff0000;
        p_rgb->color_set[1] = 0x00ff00;
        p_rgb->color_set[2] = 0x0000ff;
        p_rgb->color_set[3] = 0xff00ff;
        p_rgb->color_set[4] = 0xffff00;
        p_rgb->color_set[5] = 0x00ffff;
        p_rgb->color_set[6] = 0xffffff;
        break;
    case BRIGHTNESS /* constant-expression */:
        /* code */
        p_rgb->color_set[0] = 0x000000;
        p_rgb->color_set[1] = 0x000000;
        p_rgb->color_set[2] = 0x000000;
        p_rgb->color_set[3] = 0x000000;
        p_rgb->color_set[4] = 0x000000;
        p_rgb->color_set[5] = 0x000000;
        p_rgb->color_set[6] = 0x000000;
        /* 初始值偏移 */
        p_rgb->blue_index = 0xff;
        break;
    default:
        break;
    }
    return;
}
/**
 * @func:
 * @description: 生成rgb链表
 * @param {uint32_t} data
 * @return {*}
 * @example:
 */
link *set_link_brightness_init(uint32_t data[], uint32_t length)
{
    init_rgb_set *p_rgb = &rgb_set;

    link *p = (link *)malloc(sizeof(link)); // 创建一个头结点
    link *temp = p;                         // 声明一个指针指向头结点，用于遍历链表

    // 生成链表
    for (int i = 0; i < length; i++)
    {

        link *a = (link *)malloc(sizeof(link));

        a->elem = data[i] = change_level(p_rgb->color_set[p_rgb->color_flag], p_rgb->brightness);
        a->next = NULL;
        temp->next = a;
        temp = temp->next;
        p_rgb->brightness += 0.1;
        if (++p_rgb->color_flag >= LINK_INIT_LEN)
            p_rgb->color_flag = 0;

        if (0.9 < p_rgb->brightness)
        {

            p_rgb->brightness = 1.0;
        }
    }
    return p;
}
/**
 * @func:
 * @description: 8位RGB转32位rgb
 * @param {uint8_t} red
 * @param {uint8_t} green
 * @param {uint8_t} blue
 * @return {*}
 * @example:
 */
uint32_t color_uint8_uint32(uint8_t red, uint8_t green, uint8_t blue)
{
    uint32_t color;
    color = ((red << 16) | (green << 8) | (blue));
    return color;
}
/**
 * @func:
 * @description: RGB颜色值等比例递增
 * @param {uint32_t} rgb
 * @param {float} k
 * @return {*}
 * @example:
 */
uint32_t change_level(uint32_t rgb, float k)
{

    uint8_t r, g, b;
    float h, s, v;
    uint8_t cmax, cmin, cdes;

    r = (uint8_t)(rgb >> 16);
    g = (uint8_t)(rgb >> 8);
    b = (uint8_t)(rgb);

    cmax = r > g ? r : g;
    if (b > cmax)
        cmax = b;
    cmin = r < g ? r : g;
    if (b < cmin)
        cmin = b;
    cdes = cmax - cmin;

    v = cmax / 255.0f;
    s = cmax == 0 ? 0 : cdes / (float)cmax;
    h = 0;

    if (cmax == r && g >= b)
        h = ((g - b) * 60.0f / cdes) + 0;
    else if (cmax == r && g < b)
        h = ((g - b) * 60.0f / cdes) + 360;
    else if (cmax == g)
        h = ((b - r) * 60.0f / cdes) + 120;
    else
        h = ((r - g) * 60.0f / cdes) + 240;

    v *= k;

    float f, p, q, t;
    float rf = 0.0, gf = 0.0, bf = 0.0;
    int i = ((int)(h / 60) % 6);
    f = (h / 60) - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);
    switch (i)
    {
    case 0:
        rf = v;
        gf = t;
        bf = p;
        break;
    case 1:
        rf = q;
        gf = v;
        bf = p;
        break;
    case 2:
        rf = p;
        gf = v;
        bf = t;
        break;
    case 3:
        rf = p;
        gf = q;
        bf = v;
        break;
    case 4:
        rf = t;
        gf = p;
        bf = v;
        break;
    case 5:
        rf = v;
        gf = p;
        bf = q;
        break;
    default:
        break;
    }

    r = (uint8_t)(rf * 255.0);
    g = (uint8_t)(gf * 255.0);
    b = (uint8_t)(bf * 255.0);

    uint32_t returnColor = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
    return returnColor;
}
/**
 * @}
 */

/**
 * @}
 */

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
